#ifndef _VL_VALID__H_
#define _VL_VALID__H_

#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
#include <functional>

#include "utils/vl_file.h"
#include "prop/vl_prop_inc.h"

namespace VL {

/**
 * @Author: CimZzz
 * @Date: 2022-08-11 08:16:33
 * 
 * 预声明校验流
 */
class ValidStream;

/**
 * @Author: CimZzz
 * @Date: 2022-08-11 08:16:33
 * 
 * 预声明校验文件
 */
class ValidFile;

/**
 * @Author: CimZzz
 * @Date: 2022-08-10 23:55:26
 * 
 * 基础校验选项
 */
class BaseValidItem {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 23:54:28
	 * 
	 * 构造函数
	 * 
	 * @param code 校验码
	 */
	explicit BaseValidItem(uint32_t code, const std::string& key);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 23:55:03
	 * 
	 * 获取校验码
	 * 
	 * @return 返回校验码
	 */
	uint8_t getCode() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 08:23:44
	 * 
	 * 获取节点 Key 值
	 * 
	 * @return 返回节点 Key 值
	 */
	const std::string& getKey() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 17:12:57
	 * 
	 * 添加子校验项并返回其指针
	 * 
	 * @param childItem 子校验项指针
	 * 
	 * @return 子校验项指针
	 */
	BaseValidItem* addChildItem(BaseValidItem* childItem);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:10:45
	 * 
	 * 添加兄弟校验项, 并返回其指针
	 * 
	 * @param childItem 兄弟校验项指针
	 * 
	 * @return 兄弟校验项指针
	 * 
	 * @note 如果当前校验项是顶层, 则无动作并返回自身指针
	 */
	BaseValidItem* addBrother(BaseValidItem* childItem);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 23:58:45
	 * 
	 * 校验方法
	 * 
	 * @param prop 属性指针
	 * @param data 数据指针
	 * 
	 * @return 如果校验成功返回 true
	 */
	virtual bool valid(const std::shared_ptr<VLProp>& prop, void* data);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:26:06
	 * 
	 * 写入方法
	 * 
	 * @param mapProp 父级 Map 指针
	 * @param data 数据指针
	 */
	virtual void write(MapProp* mapProp, void* data);

private:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 17:20:31
	 * 
	 * 声明为友元类
	 */
	friend class ValidStream;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:34:39
	 * 
	 * 检验码
	 */
	uint32_t code;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 08:23:09
	 * 
	 * 节点 Key 值
	 */
	std::string key;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:10:08
	 * 
	 * 父节点
	 */
	BaseValidItem* parent;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 08:21:38
	 * 
	 * 子验证项, 当该值存在是, 默认当前验证节点为 MapProp
	 */
	std::shared_ptr<std::vector<std::shared_ptr<BaseValidItem>>> childList;
};

/**
 * @Author: CimZzz
 * @Date: 2022-08-10 16:33:10
 * 
 * 校验选项
 */
template<typename T, typename E>
class CustomValidItem: public BaseValidItem {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:38:14
	 * 
	 * 校验方法
	 * 
	 * @param 1 属性指针
	 * @param 2 对象指针
	 */
	using ValidMethod = std::function<bool(const std::shared_ptr<VLProp>&, T*)>;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:23:24
	 * 
	 * 写入方法
	 * 
	 * @param 1 父级属性 Map 指针
	 * @param 2 对象指针
	 */
	using OverrideMethod = std::function<void(MapProp*, const std::string&, E*)>;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:34:21
	 * 
	 * 构造方法
	 * 
	 * @param code 校验码
	 * @param key 节点 Key 值
	 * @param validMethod 节点验证方法
	 * @param validMethod 节点写入方法
	 */
	CustomValidItem(uint32_t code, std::string key, ValidMethod validMethod, OverrideMethod overrideMethod): BaseValidItem(code, key), validMethod(validMethod), overrideMethod(overrideMethod) {

	}

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 23:58:45
	 * 
	 * 校验方法
	 * 
	 * @param prop 属性指针
	 * @param data 数据指针
	 * 
	 * @return 如果校验成功返回 true
	 */
	virtual bool valid(const std::shared_ptr<VLProp>& prop, void* data) {
		if(!this->validMethod) {
			return true;
		}
		
		T* convertData = (T*) data;
		return this->validMethod(prop, convertData);
	}

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:26:06
	 * 
	 * 写入方法
	 * 
	 * @param mapProp 父级 Map 指针
	 * @param data 数据指针
	 */
	virtual void write(MapProp* mapProp, void* data) {
		if(!this->overrideMethod) {
			return;
		}
		E* convertData = (E*) data;
		this->overrideMethod(mapProp, this->getKey(), convertData);
	}

private:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:52:25
	 * 
	 * 验证方法
	 */
	ValidMethod validMethod;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:24:09
	 * 
	 * 写入方法
	 */
	OverrideMethod overrideMethod;
};

template<typename T>
class ValidItem : public CustomValidItem<T, T> {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:34:21
	 * 
	 * 构造方法
	 * 
	 * @param code 校验码
	 * @param key 节点 Key 值
	 * @param validMethod 节点验证方法
	 * @param validMethod 节点写入方法
	 */
	ValidItem(uint32_t code, std::string key, typename CustomValidItem<T, T>::ValidMethod validMethod, typename CustomValidItem<T, T>::OverrideMethod overrideMethod): CustomValidItem<T, T>(code, key, validMethod, overrideMethod) {

	}
};

/**
 * @Author: CimZzz
 * @Date: 2022-08-10 23:56:37
 * 
 * 验证流
 */
class ValidStream {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 00:00:28
	 * 
	 * 构造方法
	 */
	explicit ValidStream();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 07:59:41
	 * 
	 * 添加验证项
	 * 
	 * @param validItem 验证项指针
	 * 
	 * @return 验证项指针
	 */
	BaseValidItem* addValidItem(BaseValidItem* validItem);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:04:46
	 * 
	 * 校验当前全部校验选项
	 * 
	 * @param validStream 校验文件
	 * @param paramList 参数列表
	 * 
	 * @return 校验成功返回 0, 校验未知失败返回 1, 其余自定义
	 */
	uint32_t valid(ValidFile* validFile, const std::vector<void*>& paramList);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 17:15:08
	 * 
	 * 校验当前全部校验选项
	 * 
	 * @param validStream 校验文件
	 * @param paramList 参数列表
	 * 
	 * @return 校验成功返回 0, 校验未知失败返回 1, 其余自定义
	 */
	uint32_t valid(std::shared_ptr<ValidFile>& validFile, const std::vector<void*>& paramList);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:27:57
	 * 
	 * 写入当前全部校验选项
	 * 
	 * @param validStream 校验文件
	 * @param paramList 参数列表
	 */
	void write(ValidFile* validFile, const std::vector<void*>& paramList);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:27:57
	 * 
	 * 写入当前全部校验选项
	 * 
	 * @param validStream 校验文件
	 * @param paramList 参数列表
	 */
	void write(std::shared_ptr<ValidFile>& validFile, const std::vector<void*>& paramList);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-13 13:15:54
	 * 
	 * 将当前校验项写入属性表中
	 * 
	 * @param mapProp 属性表指针
	 * @param paramList 参数列表
	 */
	void writeProp(MapProp* mapProp, const std::vector<void*>& paramList);

private:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 18:31:00
	 * 
	 * 校验指定校验选项
	 * 
	 * @param prop 属性指针
	 * @param validItem 校验项指针
	 * @param begin 参数起始下标
	 * @param paramList 参数列表
	 * 
	 * @return 校验成功返回 0, 校验未知失败返回 1, 其余自定义
	 */
	uint32_t validItem(const std::shared_ptr<VLProp>& prop,  const std::shared_ptr<BaseValidItem>& validItem, uint16_t& begin, const std::vector<void*>& paramList);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:33:47
	 * 
	 * 写入指定校验选项
	 * 
	 * @param prop 父级 Map 属性指针
	 * @param validItem 校验项指针
	 * @param begin 参数起始下标
	 * @param paramList 参数列表
	 */
	void writeItem(MapProp* prop, const std::shared_ptr<BaseValidItem>& validItem, uint16_t& begin, const std::vector<void*>& paramList);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 00:00:01
	 * 
	 * 校验对象列表
	 */
	std::vector<std::shared_ptr<BaseValidItem>> validList;
};

/**
 * @Author: CimZzz
 * @Date: 2022-08-10 15:55:50
 * 
 * 检验文件方法集合
 */
class ValidFile {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 15:56:09
	 * 
	 * 构造函数
	 */
	explicit ValidFile();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-19 19:19:39
	 * 
	 * 构造函数
	 * 
	 * @param validFile 校验文件
	 */
	explicit ValidFile(const VLFile& validFile);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-19 19:19:57
	 * 
	 * 构造函数
	 * 
	 * @param validFile 校验文件指针
	 */
	explicit ValidFile(VLFile* validFilePtr);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-19 19:20:12
	 * 
	 * 构造函数
	 * 
	 * @param validFilePtr 校验文件指针
	 */
	explicit ValidFile(const std::shared_ptr<VLFile>& validFilePtr);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:02:27
	 * 
	 * 安装校验原始文件
	 * 
	 * @param validFile 校验原始文件
	 */
	void setupFile(const VLFile& validFile);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 15:58:57
	 * 
	 * 安装校验原始文件
	 * 
	 * @param validFilePtr 校验原始文件指针
	 */
	void setupFile(VLFile* validFilePtr);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:00:18
	 * 
	 * 安装校验原始文件
	 * 
	 * @param validFilePtr 校验原始文件指针
	 */
	void setupFile(const std::shared_ptr<VLFile>& validFilePtr);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:30:00
	 * 
	 * 初始化校验属性
	 * 
	 * @param isForceReload 是否强制重新加载校验属性
	 * 
	 * @return 读取成功返回 true
	 */
	bool load(bool isForceReload = false);

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 19:40:02
	 * 
	 * 写入校验属性
	 */
	void override();

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-12 14:51:54
	 * 
	 * 获取校验原始文件
	 */
	const std::shared_ptr<VLFile>& getValidFile() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:27:06
	 * 
	 * 获取校验属性
	 * 
	 * @return 校验属性指针
	 */
	const std::shared_ptr<RootProp>& getValidProp() const;

private:
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-11 17:20:31
	 * 
	 * 声明为友元类
	 */
	friend class ValidStream;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 15:58:39
	 * 
	 * 校验原始文件
	 */
	std::shared_ptr<VLFile> validFile;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-10 16:03:27
	 * 
	 * 校验属性
	 */
	std::shared_ptr<RootProp> validProp;
};



}

#endif // _VL_VALID__H_
